<?php

namespace App\Http\Middleware;

use Closure;
use Cache;
use Illuminate\Support\Facades\DB;
use App\Services\ApiService as Api;

class WxAuth
{

    const SYSTEM = 'homefee';

    const TOKEN = 'SLlfiP07cbQC5gqDGeXDmprBEALpmhKU';

    private $_config = [
        'appid'             => 'wx267d495deccf358a',
        'appsecret'         => '1d956fd9fce709887035878ad2e2d1fe',
        'token'             => 'hivesport',
        'encodingaeskey'    => 'sMhvoiV39qSNZzb7NJjGxQDEq5eJ7vYJK8IpAnUZudO',
    ];

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  string|null  $guard
     * @return mixed
     */
    public function handle($request, Closure $next, $guard = null)
    {
        $token = $request->input( 'access_token' );
        // 授权回调处理
        if ( !empty( $token ) )
        {
            // 获取用户信息
            $userinfo = null;
            if ( $this->getUserinfoByToken( $token, $userinfo ) === false )
                return response()->json( ['errcode' => 1, 'msg' => $userinfo] );

            // 保存微信用户数据
            $uid = $this->checkBind( $userinfo['openid'] );
            if ( !$uid )
                return redirect()->action( 'HomeController@bind', ['openid' => $userinfo['openid']] );
            else
            {
                $userinfo['uid'] = $uid;
                Cache::add( 'user', $userinfo, 120 );
            }
        }

        // 检测到微信未授权登录
        $user = Cache::get( 'user' );
        if ( empty( $user ) )
        {
            $timestamp = time();
            $nonce = $this->getNonceStr();
            $sign = $this->sign( $timestamp, $nonce );

            $callback = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
            $authUrl = sprintf( "http://wxauth.yumisakura.cn/auth?system=%s&timestamp=%s&nonce=%s&signature=%s&redirect_url=%s", self::SYSTEM, $timestamp, $nonce, $sign, urlencode( $callback ) );
            return redirect( $authUrl );
        }

        return $next( $request );
    }

    /**
     * 检查微信绑定
     * @param  string $openid 微信 openid
     * @return boolean         
     */
    private function checkBind( $openid )
    {
        $info = DB::table( 'home_wx_bind' )->where( ['openid' => $openid] )->first();
        return !empty( $info ) && !empty( $info->uid );
    }

    /**
     * 获取 Nonce 随机字符串
     * @param  integer $len 字符串长度
     * @return string       
     */
    private function getNonceStr( $len = 30 )
    {
        $nonce = '';
        $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        for ( $i = 0; $i <= $len; $i++ )
            $nonce .= $str[rand( 0, strlen( $str ) - 1 )];
        return $nonce;
    }

    /**
     * 生成签名
     * @param  integer $timestamp 时间戳
     * @param  string  $nonce     随机字符串
     * @return string             签名密文
     */
    public function sign( $timestamp, $nonce )
    {
        $arr = [
            'system'    => self::SYSTEM,
            'timestamp' => $timestamp,
            'nonce'     => $nonce,
            'token'     => self::TOKEN,
        ];
        ksort( $arr );
        return sha1( http_build_query( $arr ) );
    }

    /**
     * 使用授权中心下发的令牌获取对应的微信用户数据
     * @param  string $token   授权中心访问令牌
     * @param  mixed  &$result 返回数据存放数组
     * @return boolean         
     */
    public function getUserinfoByToken( $token, &$result )
    {
        $timestamp = time();
        $nonce = $this->getNonceStr();
        $sign = $this->sign( $timestamp, $nonce );

        $params = [
            'system'    => self::SYSTEM,
            'timestamp' => $timestamp,
            'nonce'     => $nonce,
            'signature' => $sign
        ];

        $Api = new Api();
        $url = $Api->buildUrl( 'http://wxauth.yumisakura.cn/userinfo', $params );
        $info = json_decode( $Api->accessUrl( $url, ['access_token' => $token] ), true );
        if ( $info['errcode'] == Api::SUCCESS )
        {
            $result = $info['data'];
            return true;
        }
        else
        {
            $result = $info['msg'];
            return false;
        }
    }
}
